package com.example.xcService.pojo.channels.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.xcService.pojo.channels.ChannelService;
import com.example.xcService.pojo.tool.HttpTool;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;


/*
*  QQ会员 (直充)
* */
@Slf4j
public class Plugin_ECARD_P039 implements ChannelService {


    @Override
    public ChannelResult QueryBalance(JSONObject apiConfig) {
        System.out.println("成功调用了QueryBalance");
        return ChannelResult.success("success");
    }




    @Override
    public ChannelResult Submit(JSONObject apiConfig, Map<String, Object> data) {
        try {
           /*业务类型(1-qq会员 2-qq超级会员 3-普通黄钻 4-豪华黄钻 5-大会员)*/

            //id/2/30/活动id
            String supProductId = String.valueOf(data.get("SUPProductId"));

            String accountVal = String.valueOf(data.get("AccountVal"));
            String appId = apiConfig.getString("AppId");
            String contractNum = apiConfig.getString("ContractNum");//合同号
            String key = apiConfig.getString("AppKey");
            String privateKey = apiConfig.getString("PrivateKey");
            String submitUrl = apiConfig.getString("SubmitUrl");

            if (!checkQQNum(accountVal)) {
                return ChannelResult.FAILED("QQ号码异常");
            }
            String[] split = supProductId.split("/");
            String productId = null;
            String activityId = null;
            if (split.length == 4) {
                //活动场景
                productId = split[0];
                activityId = split[3];
            }else {
                //非活动场景
                productId = split[0];
            }
            HashMap<String, String> submitParams = new HashMap<>();
            submitParams.put("action","direct_proivde");//直充标识
            submitParams.put("offer_id",appId);//apiId
            submitParams.put("product_id",productId);//商品id
            submitParams.put("contract_no",contractNum);//合同号

            submitParams.put("provide_no_type","uin");//发货号码类型 --QQ

            //submitParams.put("bus_no_type","");  //bus_id 时需传递该参数  - 手机号
            //submitParams.put("bus_no_extend","");//权益方帐号相关的扩展信息，格式：key1=val1&key2=val2。算签名时需要使用原串，请求时需要urlencode
            //submitParams.put("hy_gameid_type")
            submitParams.put("provide_uin",accountVal);  //只支持QQ
            //submitParams.put("provide_appid","微信openId");
            if (activityId !=null){
                submitParams.put("activity_id",activityId);
            }
            String agentPrice = String.valueOf(data.get("AgentPrice"));
            int monney =  (int)Double.parseDouble(agentPrice)*100;

            submitParams.put("sale_price",String.valueOf(monney));
            submitParams.put("sub_channel_id","other");//售卖渠道，详见售卖渠道枚举值一节，如同一个商户下方分多个渠道，且下发无枚举值，则提供需要添加的中文名+英文名给承广添加。如只有一个渠道售卖，则传默认值other即可
            submitParams.put("user_id","default");
            submitParams.put("user_name","default");
            submitParams.put("user_id_type","default");

            submitParams.put("version","1.0");
            long unixTimestamp = System.currentTimeMillis() / 1000;
            submitParams.put("ts",String.valueOf(unixTimestamp));

            submitParams.put("out_trade_no",String.valueOf(data.get("ChannelOrderCode")));
            //submitParams.put("sub_merchant_id","二级代理商、平台分配");
            //submitParams.put("ivrid","ivr单号，在ToB采购管理台上可查。(司内采购按消耗结算场景必传)");

            String sign = generateSign(submitParams, key, privateKey);//privateKey
            submitParams.put("sig",sign);//签名

            String respStr = HttpTool.HttpPost(submitUrl, submitParams);
            JSONObject respObj = JSONObject.parseObject(respStr);
            String ret = respObj.getString("ret");
            String msg = respObj.getString("msg");
            if (ret.equals("0")){
                return ChannelResult.success("充值成功");
            }else {
                return ChannelResult.FAILED(msg);
            }
        }catch (Exception e) {
            e.printStackTrace();
            log.error("QQ会员提单接口错误：",e);
            return  ChannelResult.error("QQ会员提单接口错误");
        }
    }


    @Override
    public ChannelResult Query(JSONObject apiConfig, Map<String, Object> data) {
        try {
            String appId = apiConfig.getString("AppId");
            String key = apiConfig.getString("AppKey");
            String privateKey = apiConfig.getString("PrivateKey");
            String queryUrl = apiConfig.getString("QueryUrl");

            HashMap<String, String> queryParams = new HashMap<>();
            queryParams.put("offer_id",appId);
            queryParams.put("out_trade_no",String.valueOf(data.get("ChannelOrderCode")));
            long unixTimestamp = System.currentTimeMillis() / 1000;
            queryParams.put("ts",String.valueOf(unixTimestamp));


            String sign = generateSign(queryParams, key, privateKey);
            queryParams.put("sig",sign);//签名

            String respStr = HttpTool.HttpPost(queryUrl, queryParams);
            JSONObject respObj = JSONObject.parseObject(respStr);
            String ret = respObj.getString("ret");
            String msg = respObj.getString("msg");
            if (ret.equals("0")) {
                JSONObject parseObject = JSONObject.parseObject("water_list");
                String order_state = parseObject.getString("order_state");
                if (order_state.equals("910")) {
                    return ChannelResult.success("充值成功");
                }
                if (order_state.equals("201")||order_state.equals("901")||order_state.equals("205")) {
                    return ChannelResult.FAILED(msg);
                }
            }
            return ChannelResult.error(msg);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("QQ会员查询接口错误：",e);
            return  ChannelResult.error("QQ会员查询接口错误");
        }

    }

    @Override
    public ChannelResult Notify(JSONObject apiConfig, Map<String, Object> data) {
        System.out.println("成功调用了Notify");
        return ChannelResult.success("success");
    }

    public static String generateSign(Map<String, String> params, String key,String privateKey) {
        // 1. 将参数按照键的ASCII码从小到大排序（字典序）
        Map<String, String> sortedParams = new TreeMap<>(params);

        // 2. 将非空参数值按照URL键值对的格式拼接成字符串stringA
        StringBuilder stringA = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            if (!entry.getValue().isEmpty()) {
                stringA.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }
        stringA.append(key);

        return doEncode(privateKey,stringA.toString());

    }

    private static boolean doVerify(String publicKey, String encodeResult, String contentToVerify) {
        try {
            publicKey = publicKey.replaceAll("-----END PUBLIC KEY-----", "").
                    replaceAll("-----BEGIN PUBLIC KEY-----", "").
                    replaceAll("\n", "");
            byte[] b2 = Base64.getDecoder().decode(publicKey);
            X509EncodedKeySpec xspec = new X509EncodedKeySpec(b2);

            KeyFactory kf = KeyFactory.getInstance("RSA");
            Signature privateSignature = Signature.getInstance("SHA256withRSA");

            privateSignature.initVerify(kf.generatePublic(xspec));
            privateSignature.update(contentToVerify.getBytes("UTF-8"));

            byte[] verifyBytes = Base64.getDecoder().decode(encodeResult);

            return privateSignature.verify(verifyBytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return false;
    }




    private static String doEncode(String privateKey, String contentToEncode) {
        privateKey = privateKey.replaceAll("-----END PRIVATE KEY-----", "").
                replaceAll("-----BEGIN PRIVATE KEY-----", "").
                replaceAll("\n", "");

        // 私钥需要进行Base64解密
        byte[] b1 = Base64.getDecoder().decode(privateKey);

        try {
            // 将字节数组转换成PrivateKey对象
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            Signature privateSignature = Signature.getInstance("SHA256withRSA");
            privateSignature.initSign(kf.generatePrivate(spec));

            // 输入需要签名的内容
            privateSignature.update(contentToEncode.getBytes("UTF-8"));
            // 拿到签名后的字节数组
            byte[] s = privateSignature.sign();
            // 将签名后拿到的字节数组做一个Base64编码，以便以字符串的形式保存
            return Base64.getEncoder().encodeToString(s);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return "";
    }
    private static boolean checkQQNum(String s) {
        boolean flag = false;
        if (s.length() >= 5 && s.length() <= 15 && !s.startsWith("0")) {
            for (int i = 0; i < s.length(); i++) {
                char ch = s.charAt(i);
                if (ch >= '0' && ch <= '9') {
                    flag = true;
                } else {
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    }




}
